package common.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import common.utils.model.IpAddress;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;



/**
 * 通用工具类
 *
 * @author dwen 李智辉
 * @date 2018年3月15日上午11:20:51
 * @version v1.0
 */
public class CommonUtil {
	private static final double EARTH_RADIUS = 6371393; // 平均半径,单位：m；不是赤道半径。赤道为6378左右

	/**
	 * 默认首页
	 *
	 * @param pageIndexStr
	 * @return
	 */
	public static int checkPageIndex(String pageIndexStr) {
		int pageIndex = 1;
		if (StringUtils.isNotBlank(pageIndexStr)) {
			try {
				pageIndex = Integer.parseInt(pageIndexStr);
				if (pageIndex < 1) {
					pageIndex = 1;
				}
			} catch (Exception e) {
				pageIndex = 1;
			}
		}
		return pageIndex;
	}

	public static String generateUUIDString() {
		return UUID.randomUUID().toString().replaceAll("-", "") + UUID.randomUUID().toString().replaceAll("-", "");
	}

	public static String getRandomNumber(int digCount) {
		Random rnd = new Random();
		StringBuilder sb = new StringBuilder(digCount);
		for (int i = 0; i < digCount; i++)
			sb.append((char) ('0' + rnd.nextInt(10)));
		return sb.toString();
	}

	final static String[] PHONENUMBER_PREFIX = { "130", "131", "132", "145", "155", "156", "185", "186", "134", "135",
			"136", "137", "138", "139", "147", "150", "151", "152", "157", "158", "159", "182", "183", "187", "188",
			"133", "153", "189", "180", "181", "177", "176", "172", "173", "175", "178", "179", "171" };

	/**
	 * 匹配手机号码
	 * <p>
	 * 新联通</br>
	 * （中国联通+中国网通）手机号码开头数字 130,131,132,145,155,156,185,186</br>
	 * 新移动</br>
	 * （中国移动+中国铁通）手机号码开头数字</br>
	 * 134,135,136,137,138,139,147,150,151,152,157,158,159,182,183,187,188</br>
	 * 新电信</br>
	 * （中国电信+中国卫通）手机号码开头数字 133,153,189,180</br>
	 * </p>
	 *
	 * @return 参数为null和不合法时返回false，否则返回true
	 */
	public static boolean patternPhoneNumber(String number) {
		int len = PHONENUMBER_PREFIX.length;
		if (number != null) {
			for (int i = 0; i < len; i++) {
				Pattern p = Pattern.compile(PHONENUMBER_PREFIX[i] + "\\d{8}");
				if (p.matcher(number).matches()) {
					return true;
				}
			}
		}
		return false;
	}

	public static final String MOBILE_REGEXP = "[0-9]{11}";

	/**
	 * 验证手机号码，只要是全数字，11位就可以了
	 *
	 * @param mobile
	 * @return
	 */
	public static boolean patternPhoneReduce(String mobile) {
		Pattern p = Pattern.compile(MOBILE_REGEXP);
		Matcher m = p.matcher(mobile);
		return m.matches();
	}

	/**
	 * 比较版本号的大小,前者大则返回一个正数,后者大返回一个负数,相等则返回0
	 *
	 * @param version1
	 * @param version2
	 * @return
	 */
	public static int compareVersion(String version1, String version2) throws Exception {
		if (version1 == null || version2 == null) {
			throw new Exception("compareVersion error:illegal params.");
		}
		String[] versionArray1 = version1.split("\\.");// 注意此处为正则匹配，不能用.；
		String[] versionArray2 = version2.split("\\.");
		int idx = 0;
		int minLength = Math.min(versionArray1.length, versionArray2.length);// 取最小长度值
		int diff = 0;
		while (idx < minLength && (diff = versionArray1[idx].length() - versionArray2[idx].length()) == 0// 先比较长度
				&& (diff = versionArray1[idx].compareTo(versionArray2[idx])) == 0) {// 再比较字符
			++idx;
		}
		// 如果已经分出大小，则直接返回，如果未分出大小，则再比较位数，有子版本的为大；
		diff = (diff != 0) ? diff : versionArray1.length - versionArray2.length;
		return diff;
	}

	/**
	 * 获取IP
	 * @param request
	 * @return
	 */
	public static String getIp(HttpServletRequest request) {

		String ip  =  request.getHeader("x-forwarded-for");

		if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
			ip = request.getHeader(" Proxy-Client-IP ");
		}
		if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
			ip = request.getHeader(" WL-Proxy-Client-IP ");
		}
		if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	public static int getVersionNumber(String version) {
		if (StringUtils.isNotBlank(version)) {
			String versionString = version.replace(".", "");
			return Integer.parseInt(versionString);
		} else {
			return 0;
		}
	}

	/**
	 * 计算两点距离
	 *
	 * @param lat1 起点纬度
	 * @param lng1 起点经度
	 * @param lat2 终点纬度
	 * @param lng2 终点经度
	 * @return 直线距离 单位（米）
	 */
	public static Double getDistance(Double lat1, Double lng1, Double lat2, Double lng2) {
		// 经纬度（角度）转弧度。弧度用作参数，以调用Math.cos和Math.sin
		double radiansAX = Math.toRadians(lng1); // A经弧度
		double radiansAY = Math.toRadians(lat1); // A纬弧度
		double radiansBX = Math.toRadians(lng2); // B经弧度
		double radiansBY = Math.toRadians(lat2); // B纬弧度
		// 公式中“cosβ1cosβ2cos（α1-α2）+sinβ1sinβ2”的部分，得到∠AOB的cos值
		double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX)
				+ Math.sin(radiansAY) * Math.sin(radiansBY);
		// System.out.println("cos = " + cos); // 值域[-1,1]
		double acos = Math.acos(cos); // 反余弦值
		// System.out.println("acos = " + acos); // 值域[0,π]
		// System.out.println("∠AOB = " + Math.toDegrees(acos)); // 球心角 值域[0,180]
		return EARTH_RADIUS * acos; // 最终结果
	}

	public static boolean isDoubleOrFloat(String str) {
		Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
		return pattern.matcher(str).matches();
	}

	/**
	 * 验证是不是纯中文
	 *
	 * @param str
	 * @return
	 */
	public static boolean isChineseStr(String str) {
		Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]");
		char c[] = str.toCharArray();
		for (int i = 0; i < c.length; i++) {
			Matcher matcher = pattern.matcher(String.valueOf(c[i]));
			if (!matcher.matches()) {
				return false;
			}
		}
		return true;
	}

	public static String httpPost(String postUrl, Map<String, Object> params) {
		String result = null;
		InputStream is = null;
		HttpURLConnection connection = null;
		try {
			URL url = new URL(postUrl);// 创建连接
			connection = (HttpURLConnection) url.openConnection();
			connection.setDoOutput(true);
			connection.setDoInput(true);
			connection.setUseCaches(false);
			connection.setInstanceFollowRedirects(true);
			connection.setRequestMethod("POST");// 设置请求方式
			connection.setRequestProperty("Accept", "application/json");// 设置接收数据的格式
			connection.setRequestProperty("Content-Type", "application/json");// 设置发送数据的格式
			connection.connect();
			OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");// utf-8编码
			out.append(JSON.toJSONString(params));
			out.flush();
			out.close(); // 读取响应
			int length = (int) connection.getContentLength();// 获取长度
			is = connection.getInputStream();
			if (length != -1) {
				byte[] data = new byte[length];
				byte[] temp = new byte[512];
				int readLen = 0;
				int destPos = 0;
				while ((readLen = is.read(temp)) > 0) {
					System.arraycopy(temp, 0, data, destPos, readLen);
					destPos += readLen;
				}
				result = new String(data, "UTF-8");
				System.out.println(result);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != is) {
					is.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}

		}
		return result;
	}

	/**
	 * 计算两个值的百分比
	 * 
	 * @param num1
	 * @param num2
	 * @return
	 */
	public static Double getPercentNum(int num1, int num2) {
		// 创建一个数值格式化对象
		NumberFormat numberFormat = NumberFormat.getInstance();
		// 设置精确到小数点后2位
		numberFormat.setMaximumFractionDigits(2);
		String format = numberFormat.format((float) num1 / (float) num2 * 100);
		if (format != null) {
			return Double.parseDouble(format);
		}
		return 0d;
	}

	/**
	 * 字符串转BigDecimal
	 */
	public static BigDecimal toBigDecimal(String num) {
		BigDecimal decimal = new BigDecimal(num);
		return decimal.setScale(2, RoundingMode.HALF_UP);
	}
	
	/**
	 * 根据Ip获取ip归属地、运营商、经纬度
	 * 
	 * @param ip
	 * @return IpAddress
	 */
	public static IpAddress getIpAddress(String ip){
		IpAddress addr = null;
		//API产品路径
        String requestUrl = "https://ipaddr.market.alicloudapi.com/ip_addr_search/v1?";
        //阿里云APPCODE
        String appcode = "e6bae17056084dd284b2ae03d644c141";

        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();

        querys.put("IP_ADDR", ip);

        try {
        	String rs = RestTemplateUtil.get(requestUrl, headers, querys);
        	System.out.println(rs);
        	if (StringUtils.isNotBlank(rs)) {
        		JSONObject jsonObject = JSONObject.parseObject(rs);
        		if (null != jsonObject && jsonObject.toJSONString().contains("INPUT_IP_ADDRESS")) {
        			jsonObject = (JSONObject) jsonObject.get("ENTITY");
            		addr = JSON.parseObject(jsonObject.getString("INPUT_IP_ADDRESS"), IpAddress.class);
        		}
        	}
        } catch (Exception e) {
            e.printStackTrace();
        }
	    return addr;
    }


	/**
	 * 32位大写MD5加密
	 * 
	 * @param plainText
	 * @return
	 */
	public static String stringToMD5(String plainText) {
		byte[] mdBytes = null;
		try {
			mdBytes = MessageDigest.getInstance("MD5").digest(plainText.getBytes());
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException("MD5算法不存在！");
		}
		String mdCode = new BigInteger(1, mdBytes).toString(16);

		if (mdCode.length() < 32) {
			int a = 32 - mdCode.length();
			for (int i = 0; i < a; i++) {
				mdCode = "0" + mdCode;
			}
		}
		return mdCode.toUpperCase(); // 返回32位大写
	}

	public static Integer getValueNullResultZero(Integer value) {
		if (null == value) {
			return 0;
		}
		return value;
	}

	// 随机生成Id
	public static String generateNumericId(int length) {
		SecureRandom random = new SecureRandom();
		StringBuilder id = new StringBuilder(length);

		for (int i = 0; i < length; i++) {
			int digit = random.nextInt(10); // Generate a random digit (0-9)
			id.append(digit);
		}

		return id.toString();
	}
	
	public static String truncateToTwoDecimalPlaces(String numberString) {
		try {
			// 将字符串转换为double
			double value = Double.parseDouble(numberString);
			// 乘以100后向下取整，然后再除以100
			value = Math.floor(value * 100) / 100;
			// 格式化为字符串并返回
			return String.format("%.2f", value);
		} catch (NumberFormatException e) {
			System.out.println("Invalid number format");
			return "0.00";
		}
	}

	/**
	 * 判断String数组是否包含某个元素
	 * @param array
	 * @param search
	 * @return boolean 存在-true else false
	 */
	public static boolean containsString(String[] array, String search) {
		for (String str : array) {
			if (str.contains(search)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 是否可以转为整型
	 * @param str
	 * @return
	 */
	public static boolean isInteger(String str) {
		if (str == null || str.isEmpty()) {
			return false;
		}
		try {
			Integer.parseInt(str);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}
}
